package com.witmore.neutron.ai.web.filter;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jk.common.utils.JwtUtil;
import com.witmore.neutron.ai.db.entity.AgentDO;
import com.witmore.neutron.ai.db.mapper.AgentMapper;
import com.witmore.neutron.ai.web.controller.vo.UserSession;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * Description: AccessTokenAuthenticationFilter
 * Author: 豆子高
 * Date: 2025/3/3 11:10
 */
@Component
public class AccessTokenAuthenticationFilter implements HandlerInterceptor {

    public static final String[] EXCLUDE_URLS = {"/css/**", "/js/**", "/static/**", "/favicon.ico", "/svg/**",
            "/login", "/loginCheck","/login/sms",
            "/jk-navigation", "/error",
            "/v1/api/chat/**",
            "/file/**",
            "/cognitive/chat/**",
            "/develop/**",
            "/v2/**",
            "/sms/**",
            "/wechat/callback",
            "/api/wechat/menu/**",
            "wechat/h5/stock-alert-detail/**",
            "/wechat/autoreply/**"

    };

    private static final String LOGIN_URL = "/login";

    private static final String SMS_LOGIN_URL = "/login/sms";

    private final JwtUtil jwtUtil;

    private static final PathMatcher pathMatcher = new AntPathMatcher();

    private final AgentMapper agentMapper;

    @Autowired
    public AccessTokenAuthenticationFilter(JwtUtil jwtUtil, AgentMapper agentMapper) {
        this.jwtUtil = jwtUtil;
        this.agentMapper = agentMapper;
    }
    // 1：pc 登录 2：短信登录
    private Integer loginType = 1;

    @Override
    public boolean preHandle(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception {

        // 1、获取请求的URI
        String requestURI = request.getRequestURI();
        // 当路径是根路径时 重定向到dashboard页面
//        if ("/".equals(requestURI)) {
//            response.sendRedirect("/dashboard");
//            return false;
//        }
        // 然后在检查时
        for (String pattern : EXCLUDE_URLS) {
            if (pathMatcher.match(pattern, requestURI)) {
                return true;
            }
        }
        // 2、检查是否需要忽略token验证
        if (handler instanceof HandlerMethod handlerHandler) {
            AgentLoginRequired methodAnnotation = handlerHandler.getMethodAnnotation(AgentLoginRequired.class);
            if (methodAnnotation != null) {
                try {
                    boolean agentLoginCheck = this.agentLoginCheck(request, methodAnnotation);
                    if (!agentLoginCheck) {
                        // false 要拦截
                        return true;
                    }else {
                        loginType = 2;
                    }
                } catch (Exception e) {
                    redirectToLogin(request, response);
                    return false;
                }
            }
        }
        Cookie[] cookies = request.getCookies();
        String token = null;
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("Authorization".equals(cookie.getName())) {
                    token = cookie.getValue();
                    break;
                }
            }
        }
        if (token == null || token.isEmpty()) {
            redirectToLogin(request, response);
            return false;
        }
        String claimsStr;
        try {
            claimsStr = jwtUtil.validateToken(token);
            if (claimsStr == null || claimsStr.isEmpty()) {
                redirectToLogin(request, response);
                return false;
            }
            UserSession userSession = JSONObject.parseObject(claimsStr, UserSession.class);
            // 3、将用户信息存入线程中
            GlobalAccountSession.setUserInfo(userSession);
            return true;
        } catch (Exception e) {
            redirectToLogin(request, response);
            return false;
        }
    }


    /**
     * 检查是否需要登录
     */
    private boolean agentLoginCheck(HttpServletRequest request, AgentLoginRequired methodAnnotation) {

        // 获取路径参数agentCode
        String agentCodeParam = methodAnnotation.value();
        Map<String, String> pathVariables = (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
        pathVariables = pathVariables == null ? new HashMap<>() : pathVariables;
        String agentCode = pathVariables.get(agentCodeParam);
        if (agentCode == null || agentCode.isEmpty()) {
            // 这里为空 肯定不正常 报错
            throw new RuntimeException("agentCode参数不能为空");
        }
        // 查询agentCode信息
        AgentDO agentDO = agentMapper.selectOne(new LambdaQueryWrapper<AgentDO>()
                .eq(AgentDO::getAgentCode, agentCode)
        );
        if (agentDO == null) {
            // 这里为空 肯定不正常 报错
            throw new RuntimeException("agent机器人不能为空");
        }
        // 需要登录
        return agentDO.getLoginFlag() != null && agentDO.getLoginFlag() == 1;
    }


    private void redirectToLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 保存当前请求URL用于登录后跳转
        String redirectUrl = LOGIN_URL + "?redirect=" + URLEncoder.encode(request.getRequestURI(), StandardCharsets.UTF_8);
        if (loginType != null && loginType == 2){
            redirectUrl = SMS_LOGIN_URL + "?redirect=" + URLEncoder.encode(request.getRequestURI(), StandardCharsets.UTF_8);
        }
        // 清除可能存在的旧token
        Cookie cookie = new Cookie("Authorization", null);
        cookie.setMaxAge(0);
        cookie.setPath("/");
        response.addCookie(cookie);

        response.sendRedirect(redirectUrl);
    }

}
